package com.duff.download.okdownload.async;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义线程池
 *
 * @author: duff
 * @date: 2019/3/30
 * @since: 1.0.0
 */
public class ThreadPoolImpl {

    /**
     * The default thread factory.
     */
    private static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

    private ThreadPoolExecutor mThreadPoolExecutor;
    private static final int DEF_CORE_POOL_SIZE = 8;
    private static final int DEF_MAX_POOL_SIZE = 128;
    private static final int KEEP_ALIVE_TIME = 1;
    private static final int AWAIT_TERMINATION_TIMEOUT = 10000; //ms

    public ThreadPoolImpl() {
        this(DEF_CORE_POOL_SIZE, DEF_MAX_POOL_SIZE);
    }

    public ThreadPoolImpl(int corePoolSize, int maximumPoolSize) {
        mThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                KEEP_ALIVE_TIME, TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(),
                new DefaultThreadFactory());
    }

    private void assertState() {
        if (mThreadPoolExecutor.isShutdown())
            throw new IllegalStateException("This thread pool has been shutdown !!");
    }

    private void assertTaskValidity(Object object) {
        if (object == null) {
            throw new IllegalArgumentException("Task must not be null !!");
        }
    }

    /**
     * @param task Runnable
     */
    public synchronized void execute(Runnable task) {
        assertState();
        assertTaskValidity(task);

        mThreadPoolExecutor.execute(task);
    }

    /**
     * @param task Callable
     * @param <T> type
     * @return Future
     */
    public synchronized <T> Future<T> submit(Callable<T> task) {
        assertState();
        assertTaskValidity(task);

        return mThreadPoolExecutor.submit(task);
    }

    /**
     * @param task Runnable
     * @return Future
     */
    public synchronized Future<?> submit(Runnable task) {
        assertState();
        assertTaskValidity(task);

        return mThreadPoolExecutor.submit(task);
    }

    /**
     * @param task Runnable
     * @param result
     * @param <T> type
     * @return result
     */
    public synchronized <T> Future<T> submit(Runnable task, T result) {
        assertState();
        assertTaskValidity(task);

        return mThreadPoolExecutor.submit(task, result);
    }

    /**
     * 删除任务，先清理已取消的任务，再进行移除
     *
     * @param task
     * @return 在任务队列中是否存在该任务
     */
    public synchronized boolean remove(Runnable task) {
        mThreadPoolExecutor.purge();
        return mThreadPoolExecutor.remove(task);
    }

    /**
     * 关闭任务，不再接收新任务，但会处理完正在运行的和在阻塞队列中等待处理的任务
     */
    public synchronized void shutdown() {
        mThreadPoolExecutor.shutdown();
    }

    /**
     * 关闭任务，不接收新任务，不再处理在阻塞队列中等待的任务，还会尝试中断正在处理中的工作线程
     *
     * @return A list of the tasks that were awaiting execution (workQueue中待处理的任务).
     */
    public synchronized List<Runnable> shutdownNow() {
        return mThreadPoolExecutor.shutdownNow();
    }

    /**
     * 关闭任务并等待终止 (等所有已提交的任务（包括正在跑的和队列中等待的）执行完或者等超时时间到或者线程被中断，抛出InterruptedException)
     *
     * @throws InterruptedException
     */
    public synchronized void shutdownAndTermination() throws InterruptedException {
        mThreadPoolExecutor.shutdown();
        mThreadPoolExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
    }

    /**
     * 关闭任务并等待终止 (等所有已提交的任务（包括正在跑的和队列中等待的）执行完或者等超时时间到或者线程被中断，抛出InterruptedException)
     *
     * @return A list of the tasks that were awaiting execution (workQueue中待处理的任务).
     * @throws InterruptedException
     */
    public synchronized List<Runnable> shutDownNowAndTermination() throws InterruptedException {
        List<Runnable> tasks = mThreadPoolExecutor.shutdownNow();
        mThreadPoolExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
        return tasks;
    }

    public boolean isShutDown() {
        return mThreadPoolExecutor.isShutdown();
    }

    public boolean isTerminating() {
        return mThreadPoolExecutor.isTerminating();
    }

    public boolean isTerminated() {
        return mThreadPoolExecutor.isTerminated();
    }

}
